﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Odyssey.Utils;
using System.Linq;

namespace Odyssey.Effects
{
    /// <summary>
    /// Provides the swivel effect on items on a quick jump list.
    /// </summary>
    public class QuickJumpSwivelEffect
    {

        private static Storyboard GetItemStoryboard(DependencyObject obj)
        {
            return (Storyboard)obj.GetValue(ItemStoryboardProperty);
        }

        private static void SetItemStoryboard(DependencyObject obj, Storyboard value)
        {
            obj.SetValue(ItemStoryboardProperty, value);
        }

        public static readonly DependencyProperty ItemStoryboardProperty =
            DependencyProperty.RegisterAttached("ItemStoryboard", typeof(Storyboard), typeof(QuickJumpSwivelEffect), new PropertyMetadata(null));




        public static bool GetIsElement(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsElementProperty);
        }

        public static void SetIsElement(DependencyObject obj, bool value)
        {
            obj.SetValue(IsElementProperty, value);
        }

        public static readonly DependencyProperty IsElementProperty =
            DependencyProperty.RegisterAttached("IsElement", typeof(bool), typeof(QuickJumpSwivelEffect), new PropertyMetadata(false, OnElementChanged));

        private static void OnElementChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            bool isElement = (bool)args.NewValue;

            if (isElement)
            {
                FrameworkElement e = o as FrameworkElement;
                e.Opacity = 0.0;
            }
        }




        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }

        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }

        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(QuickJumpSwivelEffect), new PropertyMetadata(false, OnEnabledChanged));

        private static void OnEnabledChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            bool isEnabled = (bool)args.NewValue;

            FrameworkElement root = o as FrameworkElement;


            if (isEnabled)
            {
                root.ScheduleOnNextRender(() =>
                    {
                        Apply(true, root);
                    });
            }
            else
            {
                Apply(isEnabled, root);
            }
        }


        private static void Apply(bool isEnabled, FrameworkElement root)
        {
            var affectedElements = root.GetVisualDescendants().Where(c => GetIsElement(c) == true).OfType<FrameworkElement>().ToList();

            TimeSpan duration = TimeSpan.FromMilliseconds(isEnabled ? 250 : 250);

            Storyboard sb = GetItemStoryboard(root);
            if (sb != null)
            {
                sb.Stop();
                sb.Children.Clear();
            }
            else
            {
                sb = new Storyboard();
                Storyboard.SetTarget(sb, root);
            }

            double targetOpacity = isEnabled ? 1d : 0d;
            IEasingFunction opacityEase = new ExponentialEase { EasingMode = isEnabled ? EasingMode.EaseOut : EasingMode.EaseIn, Exponent = 50d };
            IEasingFunction rotationEase = new ExponentialEase { EasingMode = isEnabled ? EasingMode.EaseInOut : EasingMode.EaseIn, Exponent = 5d };
            foreach (var e in affectedElements)
            {
                const double angle = 80d;
                // e.Opacity = 1.0;
                e.AdjustPerspective(root);
                PlaneProjection projection = e.Projection as PlaneProjection;
                projection.RotationX = isEnabled ? -angle : 0;

                Timeline timeline = new DoubleAnimation
                {
                    Duration = duration,
                    From = isEnabled ? -angle : 0,
                    To = isEnabled ? 0 : angle,
                    EasingFunction = rotationEase
                };

                Storyboard.SetTarget(timeline, projection);
                Storyboard.SetTargetProperty(timeline, new PropertyPath("RotationX"));
                sb.Children.Add(timeline);

                timeline = new DoubleAnimation
                {
                    Duration = duration,
                    To = targetOpacity,
                    EasingFunction = opacityEase
                };
                Storyboard.SetTarget(timeline, e);
                Storyboard.SetTargetProperty(timeline, new PropertyPath("Opacity"));
                sb.Children.Add(timeline);

            }

            sb.Begin();
        }



    }
}
